package com.dji.sample.component.websocket.config;

import com.alibaba.fastjson2.JSONObject;
import com.dji.sample.common.model.CustomClaim;
import com.dji.sample.common.model.LoginUser;
import com.dji.sample.common.util.JwtUtil;
import com.dji.sample.component.AuthInterceptor;
import com.dji.sample.manage.model.entity.UserEntity;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.Principal;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import static com.dji.sample.component.ShareAuthInterceptor.*;

/**
 * @author sean.zhou
 * @date 2021/11/16
 * @version 0.1
 */
@Slf4j
@Component
public class AuthPrincipalHandler extends DefaultHandshakeHandler {

    @Value(value = "${token.model}")
    private String model;

    @Autowired
    private HandlerInterceptor authInterceptor;

    public static final String TOKEN_CLAIM = "customClaim";

    @Resource
    RedisTemplate<String, Object> redisTemplate;

    @Value("${token.secret}")
    private String secret;

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Override
    protected boolean isValidOrigin(ServerHttpRequest request) {

        if (request instanceof ServletServerHttpRequest) {
            HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
            String token = servletRequest.getParameter(AuthInterceptor.PARAM_TOKEN);

            if (!StringUtils.hasText(token)) {
                return false;
            }
            if("share".equals(model)){
                return checkToken(token,servletRequest);
            }
            Optional<CustomClaim> customClaim = JwtUtil.parseToken(token);
            if (customClaim.isEmpty()) {
                return false;
            }

            servletRequest.setAttribute(AuthInterceptor.TOKEN_CLAIM, customClaim.get());
            return true;
        }
        return false;

    }

    /**
     * The principal's name: {workspaceId}/{userType}/{userId}
     * @param request
     * @param wsHandler
     * @param attributes
     * @return
     */
    @Override
    protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
        if (request instanceof ServletServerHttpRequest) {

            // get the custom claim
            CustomClaim claim = (CustomClaim) ((ServletServerHttpRequest) request).getServletRequest()
                    .getAttribute(AuthInterceptor.TOKEN_CLAIM);

            return () -> claim.getWorkspaceId() + "/" + claim.getUserType() + "/" + claim.getId();
        }
        return () -> null;
    }


    public boolean checkToken(String token,HttpServletRequest request) {
        // 解析对应的权限以及用户信息
        Claims claims = null;
        try {
            claims = parseToken(token);
        } catch (Exception e) {
            //可能是飞手端放行
            return privateToken(token, request);
        }
        // 解析对应的权限以及用户信息
        String uuid = (String) claims.get(LOGIN_USER_KEY);
        String userKey = getTokenKey(uuid);
        String val = stringRedisTemplate.opsForValue().get(userKey);
        if(val==null){
            return false;
        }
        val=val.replace("Set","");
        LoginUser user = JSONObject.parseObject(val,LoginUser.class);
        if (user == null || !token.equals(user.getToken())) {
            return false;
        }
        String userName = (String) claims.get(USER_NAME);
        //查询用户信息
        //先缓存 后查库
        String key = "dj:share:token:user:" + userName;
        CustomClaim customClaim = (CustomClaim) redisTemplate.opsForValue().get(key);
        if (customClaim == null) {
            return false;
        }
        request.setAttribute(TOKEN_CLAIM, customClaim);
        return true;
    }

    private Claims parseToken(String token) {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }

    private String getTokenKey(String uuid) {
        return LOGIN_TOKEN_KEY + uuid;
    }

    public boolean privateToken(String token, HttpServletRequest request) {
        Optional<CustomClaim> customClaimOpt = JwtUtil.parseToken(token);
        if (customClaimOpt.isEmpty()) {
            return false;
        }
        if (!Objects.equals(redisTemplate.opsForValue().get(JwtUtil.getCacheKey(customClaimOpt.get().getId(), customClaimOpt.get().getUserType().toString())), token)) {
            return false;
        }
        // Put the custom data from the token into the request.
        request.setAttribute(TOKEN_CLAIM, customClaimOpt.get());
        return true;

    }
}